﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JOATServer.SocietyFramework.Core.XML
{
    public partial class XMLAutomaton : BaseXMLAutomaton
    {
        /**
         * Dictionary containing the precedence of the operators. The keys are the class objects of each operator class.
         */
        protected static Dictionary<Type, Int32> precedence = new Dictionary<Type, Int32>();
        static XMLAutomaton()
        {
            precedence.Add(typeof(MultiplicationInstruction), 4);
            precedence.Add(typeof(DivisionInstruction), 4);
            precedence.Add(typeof(ModuloInstruction), 4);
            precedence.Add(typeof(AdditionInstruction), 3);
            precedence.Add(typeof(SubtractionInstruction), 3);
            precedence.Add(typeof(LessInstruction), 2);
            precedence.Add(typeof(LessOrEqualInstruction), 2);
            precedence.Add(typeof(GreaterInstruction), 2);
            precedence.Add(typeof(GreaterOrEqualInstruction), 2);
            precedence.Add(typeof(EqualsInstruction), 2);
            precedence.Add(typeof(NotEqualsInstruction), 2);
            precedence.Add(typeof(AndInstruction), 1);
            precedence.Add(typeof(OrInstruction), 1);
            precedence.Add(typeof(NotInstruction), 1);
            precedence.Add(typeof(AssignInstruction), 0);
            precedence.Add(typeof(OpenedBracketInstruction), -1);
            precedence.Add(typeof(ClosedBracketInstruction), -1);
        }

        /// <summary>
        /// Class which represents the opened bracket. It is used only for parsing XML Automatons, it is not included in the
        /// instruction tree.
        /// </summary>
        protected class OpenedBracketInstruction : Instruction
        {
            public BaseXMLAutomaton Owner { get; set; }
            public object Code()
            {
                return null;
            }
        }

        /// <summary>
        /// Class which represents the closed bracket. It is used only for parsing XML Automatons, it is not included in the
        /// instruction tree.
        /// </summary>
        protected class ClosedBracketInstruction : Instruction
        {
            public BaseXMLAutomaton Owner { get; set; }
            public object Code()
            {
                return null;
            }
        }

        /// <summary>
        /// Given a String expression it constructs an instruction tree representing the expression and returns it.
        /// </summary>
        /// <param name="expression">the String representation of the expression</param>
        /// <returns>the Instruction tree representing the expression</returns>
        protected Instruction ConstructExpression(String expression)
        {
            Stack<Instruction> operators = new Stack<Instruction>();
            Stack<Instruction> operands = new Stack<Instruction>();
            Instruction currentToken;						    //holds the current token received from the lexer
            //the automaton which extracts the tokens
            LexerAutomaton lexer = new LexerAutomaton(this, deserializationAutomaton.containerStack);
            bool hasMoreTokens = true;

            currentToken = new OpenedBracketInstruction();
            lexer.Expression = expression;

            while (true)
            {
                if (currentToken is OpenedBracketInstruction)
                {	//if it finds opened bracket it pushes it on operators stack
                    operators.Push(currentToken);
                }
                else if (currentToken is ClosedBracketInstruction)
                {	//if it finds closed bracket
                    while (!(operators.Peek() is OpenedBracketInstruction))
                    {
                        //it pops from the operators stack until opened bracket is found
                        Instruction operatorr = operators.Pop();
                        if (operatorr is OneOperandInstruction)
                        {					//unary operator
                            ((OneOperandInstruction)operatorr).operand = operands.Pop();
                            operands.Push(operatorr);
                        }
                        else if (operatorr is TwoOperandsInstruction)
                        {			//binary operator
                            ((TwoOperandsInstruction)operatorr).rightOperand = operands.Pop();
                            ((TwoOperandsInstruction)operatorr).leftOperand = operands.Pop();
                            operands.Push(operatorr);
                        }
                    }
                    operators.Pop();	//at the end it pops the opened bracket from the operators stack

                }
                else if (currentToken is OneOperandInstruction || currentToken is TwoOperandsInstruction)
                {
                    Instruction operatorr = operators.Pop();
                    //pops until it finds an operator with lower precedence
                    while (precedence[operatorr.GetType()] >= precedence[currentToken.GetType()])
                    {
                        if (operatorr is OneOperandInstruction)
                        {					//unary operator
                            ((OneOperandInstruction)operatorr).operand = operands.Pop();
                            operands.Push(operatorr);
                        }
                        else if (operatorr is TwoOperandsInstruction)
                        {			//binary operator
                            ((TwoOperandsInstruction)operatorr).rightOperand = operands.Pop();
                            ((TwoOperandsInstruction)operatorr).leftOperand = operands.Pop();
                            operands.Push(operatorr);
                        }

                        operatorr = operators.Pop();
                    }
                    //at the ends it pushes the popped operator and the current token in the operators stack
                    operators.Push(operatorr);
                    operators.Push(currentToken);

                }
                else
                {				//if all the above failed, then it's an operand and it's pushed on the operands stack
                    operands.Push(currentToken);
                }

                //get the next token
                lexer.Run();
                if (lexer.ResultInstruction != null && hasMoreTokens)
                {
                    currentToken = lexer.ResultInstruction;
                }
                else if (hasMoreTokens)
                {
                    currentToken = new ClosedBracketInstruction();
                    hasMoreTokens = false;
                }
                else
                {
                    break;
                }
            }

            try
            {
                return operands.Pop();		//at the end the element remaining in the operands stack is the result
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Automaton that parses an expression until it finds a token and transforms it in an Instruction.
        /// </summary>
        protected class LexerAutomaton : Automaton
        {
            protected static readonly string IDLE_STATE = "IDLE_STATE";
            protected static readonly string PROCESS_STATE = "PROCESS_STATE";
            protected static readonly string NAME = "NAME";
            protected static readonly string INDEX = "INDEX";
            protected static readonly string PARAMETERS = "PARAMETERS";
            protected static readonly string VARIABLE = "VARIABLE";
            protected static readonly string VARIABLE_WITH_INDEX = "VARIABLE_WITH_INDEX";
            protected static readonly string FUNCTION = "FUNCTION";
            protected static readonly string NUMBER = "NUMBER";
            protected static readonly string RATIONAL_NUMBER = "RATIONAL_NUMBER";
            protected static readonly string INTEGER_VALUE = "INTEGER_VALUE";
            protected static readonly string DOUBLE_VALUE = "DOUBLE_VALUE";
            protected static readonly string STRING_VALUE = "STRING_VALUE";
            protected static readonly string BOOLEAN_VALUE = "BOOLEAN_VALUE";
            protected static readonly string CHECK_OPERATOR = "CHECK_OPERATOR";
            protected static readonly string OPERATOR = "OPERATOR";
            protected static readonly string END_STATE = "END_STATE";

            //signifies that the character doesn't exist (the cursor passed the end of expression)
            protected static readonly char NULL_CHAR = '\0';

            protected List<object> accumulators;            //holds the significant values of the token
            protected char currentChar;                     //auxiliary used to retain the character at the cursor position
            public string Expression { get; set; }          //holds the expression passed by the ExpressionBuilderAtuomaton
            public int Cursor { get; set; }                 //holds the position of the cursor
            public Instruction ResultInstruction { get; set; }	//holds the instruction passed as a result

            public LexerAutomaton(XMLAutomaton automaton, Stack<CodeContainer> containerStack)
                : base()
            {
                currentStateName = IDLE_STATE;
                Cursor = -1;

                states.Add(IDLE_STATE, new IdleState(this, automaton));
                states[IDLE_STATE].transition = new SimpleTransition(this, PROCESS_STATE);

                states.Add(PROCESS_STATE, new StepState(this));
                states[PROCESS_STATE].transition = new ProcessStateTransition(this);

                states.Add(NAME, new AccumulateAndStepState(this));
                states[NAME].transition = new NameStateTransition(this);

                states.Add(INDEX, new IndexState(this, automaton));
                states[INDEX].transition = new IndexStateTransition(this);

                states.Add(VARIABLE, new LexerAutomaton.VariableState(this, automaton));
                states[VARIABLE].transition = new SimpleTransition(this, END_STATE);

                states.Add(VARIABLE_WITH_INDEX, new VariableWithIndexState(this, automaton));
                states[VARIABLE_WITH_INDEX].transition = new SimpleTransition(this, END_STATE);

                states.Add(PARAMETERS, new ParametersState(this, automaton));
                states[PARAMETERS].transition = new ParametersStateTransition(this);

                states.Add(FUNCTION, new FunctionState(this, automaton, containerStack));
                states[FUNCTION].transition = new SimpleTransition(this, END_STATE);

                states.Add(NUMBER, new AccumulateAndStepState(this));
                states[NUMBER].transition = new NumberStateTransition(this);

                states.Add(RATIONAL_NUMBER, new AccumulateAndStepState(this));
                states[RATIONAL_NUMBER].transition = new RationalNumberStateTransition(this);

                states.Add(INTEGER_VALUE, new IntegerValueState(this, automaton));
                states[INTEGER_VALUE].transition = new SimpleTransition(this, END_STATE);

                states.Add(DOUBLE_VALUE, new DoubleValueState(this, automaton));
                states[DOUBLE_VALUE].transition = new SimpleTransition(this, END_STATE);

                states.Add(STRING_VALUE, new StringValueState(this, automaton));
                states[STRING_VALUE].transition = new SimpleTransition(this, END_STATE);

                states.Add(BOOLEAN_VALUE, new BooleanValueState(this, automaton));
                states[BOOLEAN_VALUE].transition = new SimpleTransition(this, END_STATE);

                states.Add(CHECK_OPERATOR, new NullState(this));
                states[CHECK_OPERATOR].transition = new CheckOperatorStateTransition(this);

                states.Add(OPERATOR, new OperatorState(this, automaton));
                states[OPERATOR].transition = new SimpleTransition(this, END_STATE);

                states.Add(END_STATE, new EndState(this, automaton));
                states[END_STATE].transition = new SimpleTransition(this, IDLE_STATE);
            }


            /* IDLE */
            protected class IdleState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public IdleState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    automaton.accumulators = new List<Object>();
                    automaton.accumulators.Add(new StringBuilder());
                }

            };

            /* PROCESS */
            protected class ProcessStateTransition : Transition
            {
                public ProcessStateTransition(BaseAutomaton owner) : base(owner) { }

                public override string TransitionCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    if (automaton.currentChar == NULL_CHAR)
                    {	//expression finish
                        automaton.ResultInstruction = null;
                        return END_STATE;
                    }
                    else if (automaton.currentChar == ' ')
                    {
                        return PROCESS_STATE;
                    }
                    else if (Char.IsLetter(automaton.currentChar))
                    {
                        return NAME;
                    }
                    else if (Char.IsDigit(automaton.currentChar))
                    {
                        return NUMBER;
                    }
                    else if (automaton.currentChar == '\'')
                    {
                        return STRING_VALUE;
                    }
                    else if (automaton.currentChar == '.')
                    {
                        return BOOLEAN_VALUE;
                    }
                    else if (automaton.currentChar == '-')
                    {
                        return CHECK_OPERATOR;
                    }
                    else
                    {
                        return OPERATOR;
                    }
                }

            };

            /* NAME */
            protected class NameStateTransition : Transition
            {
                public NameStateTransition(BaseAutomaton owner) : base(owner) { }

                public override string TransitionCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    if (Char.IsLetterOrDigit(automaton.currentChar) || automaton.currentChar == '_')
                    {
                        return NAME;
                    }
                    else if (automaton.currentChar == '[')
                    {
                        return INDEX;
                    }
                    else if (automaton.currentChar == '(')
                    {
                        return PARAMETERS;
                    }
                    else
                    {
                        return VARIABLE;
                    }
                }

            };

            /* INDEX */
            protected class IndexState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public IndexState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    //calculate where the expression starts and ends
                    bool insideString = false;
                    int initialCursorPosition = automaton.Cursor + 1, bracketOpened = 1;
                    while (true)
                    {
                        automaton.NextChar();
                        if (automaton.currentChar == '\'')
                        {
                            insideString = !insideString;
                        }
                        if (!insideString)
                        {
                            if (automaton.currentChar == '[')
                            {
                                bracketOpened++;
                            }
                            else if (automaton.currentChar == ']')
                            {
                                if (bracketOpened == 1)
                                {
                                    break;
                                }
                                else
                                {
                                    bracketOpened--;
                                }
                            }
                        }
                    }

                    //create an instruction from the expression and add it to the accumulators list
                    automaton.accumulators.Add(ConstructedAutomaton.ConstructExpression(
                        automaton.Expression.Substring(initialCursorPosition, automaton.Cursor - initialCursorPosition)));
                    automaton.NextChar();
                }

            };

            protected class IndexStateTransition : Transition
            {
                public IndexStateTransition(BaseAutomaton owner) : base(owner) { }

                public override string TransitionCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    if (automaton.currentChar == '[')
                    {
                        return INDEX;
                    }
                    else
                    {
                        return VARIABLE_WITH_INDEX;
                    }
                }

            };

            /* VARIABLE */
            protected class VariableState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public VariableState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    VariableInstruction var = new VariableInstruction(ConstructedAutomaton);
                    var.name = automaton.accumulators[0].ToString();
                    automaton.ResultInstruction = var;
                    automaton.Cursor--;
                }

            };

            /* VARIABLE WITH INDEX */
            protected class VariableWithIndexState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public VariableWithIndexState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    VariableWithIndexInstruction vwii = new VariableWithIndexInstruction(ConstructedAutomaton);
                    vwii.name = automaton.accumulators[0].ToString();
                    vwii.indexValues = new List<Instruction>();
                    for (int i = 1; i < automaton.accumulators.Count; i++)
                    {
                        vwii.indexValues.Add((Instruction)automaton.accumulators[i]);
                    }
                    automaton.ResultInstruction = vwii;
                    automaton.Cursor--;
                }

            };

            /* PARAMETERS */
            protected class ParametersState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public ParametersState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    //calculate where the first parameter starts and ends
                    bool insideString = false;
                    int initialCursorPosition = automaton.Cursor + 1, bracketOpened = 1;

                    while (true)
                    {
                        automaton.NextChar();
                        if (automaton.currentChar == '\'')
                        {
                            insideString = !insideString;
                        }
                        if (!insideString)
                        {
                            if (automaton.currentChar == '(')
                            {
                                bracketOpened++;
                            }
                            else if (automaton.currentChar == ')')
                            {
                                if (bracketOpened == 1)
                                {
                                    break;
                                }
                                else
                                {
                                    bracketOpened--;
                                }
                            }
                            else if (automaton.currentChar == ',' && bracketOpened == 1)
                            {
                                break;
                            }
                        }
                    }

                    //create an instruction from the parameter and add it to the accumulators list
                    Instruction parameter = ConstructedAutomaton.ConstructExpression(
                        automaton.Expression.Substring(initialCursorPosition, automaton.Cursor - initialCursorPosition));
                    if (parameter != null)
                    {
                        automaton.accumulators.Add(parameter);
                    }
                }

            };

            protected class ParametersStateTransition : Transition
            {
                public ParametersStateTransition(BaseAutomaton owner) : base(owner) { }

                public override string TransitionCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    if (automaton.currentChar == ',')
                    {
                        return PARAMETERS;
                    }
                    else
                    {
                        return FUNCTION;
                    }
                }

            };

            /* FUNCTION */
            protected class FunctionState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }
                protected Stack<CodeContainer> ContainerStack { get; set; }

                public FunctionState(BaseAutomaton owner, XMLAutomaton constructedAutomaton, Stack<CodeContainer> containerStack)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                    this.ContainerStack = containerStack;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    //create the specific function from the name in the first accumulator
                    FunctionInstruction fi;
                    String functionName = automaton.accumulators[0].ToString();
                    if (functionName.Equals(GET_CURRENT_MESSAGE_FROM_FUNCTION))
                    {
                        fi = new GetCurrentMessageFromInstruction(ConstructedAutomaton);
                    }
                    else if (functionName.Equals(GET_CURRENT_MESSAGE_DATA_FUNCTION))
                    {
                        fi = new GetCurrentMessageDataInstruction(ConstructedAutomaton);
                    }
                    else if (functionName.Equals(IS_CURRENT_MESSAGE_NULL_FUNCTION))
                    {
                        fi = new IsCurrentMessageNullInstruction(ConstructedAutomaton);
                    }
                    else if (functionName.Equals(EXECUTE_TRANSITION_FUNCTION))
                    {
                        ExecuteTransitionInstruction eti = new ExecuteTransitionInstruction(ConstructedAutomaton);
                        for (int i = ContainerStack.Count - 1; i >= 0; i--)
                        {
                            if (ContainerStack.ElementAt<CodeContainer>(i) is TransitionGroup)
                            {
                                eti.owner = (TransitionGroup)ContainerStack.ElementAt<CodeContainer>(i);
                                break;
                            }
                        }
                        fi = eti;
                    }
                    else if (functionName.Equals(SIZE_FUNCTION))
                    {
                        fi = new SizeInstruction(ConstructedAutomaton);
                    }
                    else if (functionName.Equals(SPLIT_FUNCTION))
                    {
                        fi = new SplitInstruction(ConstructedAutomaton);
                    }
                    else if (functionName.Equals(PARSE_INTEGER_FUNCTION))
                    {
                        fi = new ParseIntegerInstruction(ConstructedAutomaton);
                    }
                    else
                    {
                        fi = null;
                    }

                    //add the parameters from the rest of the list
                    int numberOfParameters = automaton.accumulators.Count - 1;
                    if (numberOfParameters > 0)
                    {
                        fi.parameters = new Instruction[automaton.accumulators.Count - 1];
                        for (int i = 1; i < automaton.accumulators.Count; i++)
                        {
                            fi.parameters[i - 1] = (Instruction)automaton.accumulators[i];
                        }
                    }
                    automaton.ResultInstruction = fi;
                }

            };

            /* NUMBER */
            protected class NumberStateTransition : Transition
            {
                public NumberStateTransition(BaseAutomaton owner) : base(owner) { }

                public override string TransitionCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    if (Char.IsDigit(automaton.currentChar))
                    {
                        return NUMBER;
                    }
                    else if (automaton.currentChar == '.')
                    {
                        return RATIONAL_NUMBER;
                    }
                    else
                    {
                        return INTEGER_VALUE;
                    }
                }

            };

            /* RATIONAL NUMBER */
            protected class RationalNumberStateTransition : Transition
            {
                public RationalNumberStateTransition(BaseAutomaton owner) : base(owner) { }

                public override string TransitionCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    if (Char.IsDigit(automaton.currentChar))
                    {
                        return RATIONAL_NUMBER;
                    }
                    else
                    {
                        return DOUBLE_VALUE;
                    }
                }

            };

            /* INTEGER VALUE */
            protected class IntegerValueState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public IntegerValueState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    ValueInstruction val = new ValueInstruction(ConstructedAutomaton);
                    val.value = Int32.Parse(automaton.accumulators[0].ToString());
                    automaton.ResultInstruction = val;
                    automaton.Cursor--;
                }

            };

            /* DOUBLE VALUE */
            protected class DoubleValueState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public DoubleValueState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    ValueInstruction val = new ValueInstruction(ConstructedAutomaton);
                    val.value = Double.Parse(automaton.accumulators[0].ToString());
                    automaton.ResultInstruction = val;
                    automaton.Cursor--;
                }

            };

            /* STRING VALUE */
            protected class StringValueState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public StringValueState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    ValueInstruction val = new ValueInstruction(ConstructedAutomaton);
                    //calculate where the string starts and ends
                    int initialCursorPosition = automaton.Cursor + 1;
                    do
                    {
                        automaton.NextChar();
                    } while (automaton.currentChar != '\'');

                    val.value = automaton.Expression.Substring(initialCursorPosition, automaton.Cursor - initialCursorPosition);
                    automaton.ResultInstruction = val;
                }

            };

            /* BOOLEAN VALUE */
            protected class BooleanValueState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public BooleanValueState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    ValueInstruction val = new ValueInstruction(ConstructedAutomaton);
                    //calculate where the boolean expression starts and ends
                    int initialCursorPosition = automaton.Cursor + 1;
                    do
                    {
                        automaton.NextChar();
                    } while (automaton.currentChar != '.');

                    val.value = (automaton.Expression.Substring(initialCursorPosition, automaton.Cursor - initialCursorPosition)
                                    .Equals("T"));
                    automaton.ResultInstruction = val;
                }

            };

            /* CHECK OPERATOR */
            protected class CheckOperatorStateTransition : Transition
            {
                public CheckOperatorStateTransition(BaseAutomaton owner) : base(owner) { }

                public override string TransitionCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    if (automaton.ResultInstruction == null 			//check if there was no previous instruction
                            || automaton.ResultInstruction is OneOperandInstruction 	//or if it was an operator
                            || automaton.ResultInstruction is TwoOperandsInstruction)
                    {
                        return NUMBER;
                    }
                    else
                    {
                        return OPERATOR;
                    }
                }

            };

            /* OPERATOR */
            protected class OperatorState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public OperatorState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);

                    if (automaton.currentChar == '+')
                    {
                        automaton.ResultInstruction = new AdditionInstruction(ConstructedAutomaton);
                    }
                    else if (automaton.currentChar == '-')
                    {
                        automaton.ResultInstruction = new SubtractionInstruction(ConstructedAutomaton);
                    }
                    else if (automaton.currentChar == '*')
                    {
                        automaton.ResultInstruction = new MultiplicationInstruction(ConstructedAutomaton);
                    }
                    else if (automaton.currentChar == '/')
                    {
                        automaton.ResultInstruction = new DivisionInstruction(ConstructedAutomaton);
                    }
                    else if (automaton.currentChar == '%')
                    {
                        automaton.ResultInstruction = new ModuloInstruction(ConstructedAutomaton);
                    }
                    else if (automaton.currentChar == '=')
                    {
                        if (automaton.Expression[automaton.Cursor + 1] != '=')
                        {
                            automaton.ResultInstruction = new AssignInstruction(ConstructedAutomaton);
                        }
                        else
                        {
                            automaton.Cursor++;
                            automaton.ResultInstruction = new EqualsInstruction(ConstructedAutomaton);
                        }
                    }
                    else if (automaton.currentChar == '!')
                    {
                        if (automaton.Expression[automaton.Cursor + 1] != '=')
                        {
                            automaton.ResultInstruction = new NotInstruction(ConstructedAutomaton);
                        }
                        else
                        {
                            automaton.Cursor++;
                            automaton.ResultInstruction = new NotEqualsInstruction(ConstructedAutomaton);
                        }
                    }
                    else if (automaton.currentChar == '<')
                    {
                        if (automaton.Expression[automaton.Cursor + 1] != '=')
                        {
                            automaton.ResultInstruction = new LessInstruction(ConstructedAutomaton);
                        }
                        else
                        {
                            automaton.Cursor++;
                            automaton.ResultInstruction = new LessOrEqualInstruction(ConstructedAutomaton);
                        }
                    }
                    else if (automaton.currentChar == '>')
                    {
                        if (automaton.Expression[automaton.Cursor + 1] != '=')
                        {
                            automaton.ResultInstruction = new GreaterInstruction(ConstructedAutomaton);
                        }
                        else
                        {
                            automaton.Cursor++;
                            automaton.ResultInstruction = new GreaterOrEqualInstruction(ConstructedAutomaton);
                        }
                    }
                    else if ((automaton.currentChar == '&') && (automaton.Expression[automaton.Cursor + 1] == '&'))
                    {
                        automaton.Cursor++;
                        automaton.ResultInstruction = new AndInstruction(ConstructedAutomaton);
                    }
                    else if ((automaton.currentChar == '|') && (automaton.Expression[automaton.Cursor + 1] == '|'))
                    {
                        automaton.Cursor++;
                        automaton.ResultInstruction = new OrInstruction(ConstructedAutomaton);
                    }
                    else if (automaton.currentChar == '(')
                    {
                        automaton.ResultInstruction = new OpenedBracketInstruction();
                    }
                    else if (automaton.currentChar == ')')
                    {
                        automaton.ResultInstruction = new ClosedBracketInstruction();
                    }
                }

            };

            /* END STATE */
            protected class EndState : State
            {
                protected XMLAutomaton ConstructedAutomaton { get; set; }

                public EndState(BaseAutomaton owner, XMLAutomaton constructedAutomaton)
                    : base(owner)
                {
                    this.ConstructedAutomaton = constructedAutomaton;
                }

                public override void StateCode()
                {
                    LexerAutomaton automaton = ((LexerAutomaton)Owner);
                    automaton.StopSafely();
                }

            };


            /// <summary>
            /// Moves the cursor forward with one position and updates the currentChar. If the cursor passes the
            /// end of the expression, then the currentChar takes NULL_CHAR value.
            /// </summary>
            protected void NextChar()
            {
                Cursor++;
                if (Cursor < Expression.Length)
                {
                    currentChar = Expression.ElementAt<char>(Cursor);
                }
                else
                {
                    currentChar = NULL_CHAR;
                }
            }

            /// <summary>
            /// Appends the current character to the first accumulator which is the name accumulator.
            /// </summary>
            protected void AddToFirstAccumulator()
            {
                ((StringBuilder)accumulators[0]).Append(currentChar);
            }

            /// <summary>
            /// A state which calls NextChar().
            /// </summary>
            protected class StepState : State
            {
                public StepState(LexerAutomaton owner) : base(owner) { }

                public override void StateCode()
                {
                    ((LexerAutomaton)Owner).NextChar();
                }

            }

            /// <summary>
            /// A state which calls AddToFirstAccumulator(), then NextChar().
            /// </summary>
            protected class AccumulateAndStepState : State
            {
                public AccumulateAndStepState(LexerAutomaton owner) : base(owner) { }

                public override void StateCode()
                {
                    ((LexerAutomaton)Owner).AddToFirstAccumulator();
                    ((LexerAutomaton)Owner).NextChar();
                }

            }
        }
    }
}
